/*
 * 
 * 
 */

package steg.steki.pm3;

import steg.steki.StegException;

/**
 *
 * @author
 */
public class MP3FrameHeader {




// ------------------------------- ZIENNE PRYWATNE -----------------------------
    //-- stałe
    //-- czy
    //-- zmienne
    private long fhLoc = 0; // jego pozycja
    private int fhMpegVer = -1;
    private int fhMpegLayer = -1;
    private int fhProtection = -1;
    private int fhBitrateBit = -1;  //dla bitowej reprezentacji
    private int fhBitrateInt = -1;  // i dla liczby jej odpowieadajacej
    private int fhSamplingRateBit = -1; //.. analogicznie jak powyzej
    private int fhSampleingRateInt = -1; //..
    private int fhPadding = -1;
    private int fhPrivateBit = -1;
    private int fhChannelMode = -1;
    private int fhModeExtension = -1;
    private int fhCopyright = -1;
    private int fhOriginal = -1;
    private int fhEmphasis = -1;
    private int fhFrameSize = -1;


// ------------------------------- ZIENNE PUBLICZNE
    //-- czy
    //-- zmienne

// ------------------------------- KONSTRUKTORY

    /**
     * pusty konstruktor
     */
     public MP3FrameHeader() {

     }

// ******************************** PUBLICZNE **********************************
// *****************************************************************************
// ------------------------------- FUNKCJE KRYTYCZNE ---------------------------
    /**
     * Sprawdza nagłówek.
     * 4 bajty MP3 frame header. W razie błędu zwróci false.
     *
     * @param iTag
     * @return
     * @throws steg.pliki.StegException
     */
    public boolean init(int iTag) throws StegException {

        // pierwsze A to 1 AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
        //                 11111111 11100000 00000000 00000000
        // http://www.mp3-tech.org/programmer/frame_header.html

        // pierwszy bajt to muszą być jedynki
        if ((iTag & 0xFF000000) != 0xFF000000)
            return false;


        // są teraz czy są 3 AAA w drugim bajcie
        if ((iTag & 0xE00000) != 0xE00000)
            return false;

        //teraz dane z BBCCD

        /* BB
        MPEG Audio version ID
        11 - MPEG Version 1 (ISO/IEC 11172-3) <-- interesująca*/
        fhMpegVer = (iTag & 0x180000) >> (3+2*8);
        if (fhMpegVer != 3) {
            throw new StegException(new Exception("steg ex, kodek nie mpeg1"), StegException.BLAD_WERSJA_NIEOBSLUGIWANA, "Kodek inny niż MPEG Version 1 (ISO/IEC 11172-3). \nWersja = " + Integer.toBinaryString(fhMpegVer));
        }

        // CC
        //  01 - Layer III
        fhMpegLayer = (iTag & 0x60000) >> (1+2*8);
        if (fhMpegLayer != 1)
            throw new StegException(new Exception("steg ex, kodek nie mpeg1"), StegException.BLAD_WERSJA_NIEOBSLUGIWANA, "Warstwa inna niż Layer III.\n Layer = " + Integer.toBinaryString(fhMpegVer));

        // D
        fhProtection = (iTag & 0x10000) >> (2*8);

        // 3 bajt
        // EEEE
        fhBitrateBit = (iTag & 0xF000) >> (4+8);

        // jesli jedynki to błąd !
        if(fhBitrateBit == 0xF)
            throw new StegException(new Exception("steg ex, 1111"), StegException.BLAD_WERSJA_NIEOBSLUGIWANA, "Bitrate źle określony.\nBitrate = " + fhBitrateBit );
        if(fhBitrateBit == 0)
            throw new StegException(new Exception("steg ex, 0000"), StegException.BLAD_WERSJA_NIEOBSLUGIWANA, "Bitrate typu free, nieobsługiwany.\nBitrate = " + fhBitrateBit );

            // i dorazu na int
        if (fhBitrateBit == 1) fhBitrateInt = 32;
        if (fhBitrateBit == 2)  fhBitrateInt =  40;
        if (fhBitrateBit == 3)    fhBitrateInt =  48;
        if (fhBitrateBit == 4)    fhBitrateInt =  56;
        if (fhBitrateBit == 5)    fhBitrateInt =  64;
        if (fhBitrateBit == 6)    fhBitrateInt =  80;
        if (fhBitrateBit == 7)    fhBitrateInt =  96;
        if (fhBitrateBit == 8)    fhBitrateInt =  112;
        if (fhBitrateBit == 9)    fhBitrateInt =  128;
        if (fhBitrateBit == 10)    fhBitrateInt =  160;
        if (fhBitrateBit == 11)    fhBitrateInt =  192;
        if (fhBitrateBit == 12)    fhBitrateInt =  224;
        if (fhBitrateBit == 13)    fhBitrateInt =  256;
        if (fhBitrateBit == 14)    fhBitrateInt =  320;


        // FF
        fhSamplingRateBit = (iTag & 0xC00) >> (2+8);
            //odrazu na int
        fhSampleingRateInt = -1;
        if (fhSamplingRateBit == 0)fhSampleingRateInt = 44100;
        if (fhSamplingRateBit == 1)fhSampleingRateInt = 48000;
        if (fhSamplingRateBit == 2)fhSampleingRateInt = 32000;
        // G
        fhPadding = (iTag & 0x200) >> (1+8);
        // H
        fhPrivateBit = (iTag & 0x100) >> 8;
        //4bajt
        // II
        fhChannelMode = (iTag & 0xC0) >> 6;
        // JJ
        fhModeExtension = (iTag & 0x30) >> 4;
        // K
        fhCopyright = (iTag & 0x8) >> 3;
        // L
        fhOriginal = (iTag & 0x4) >> 2;
        // MM
        fhEmphasis = (iTag & 0x3);

        fhFrameSize = (144 * fhBitrateInt*1000) / fhSampleingRateInt;
        if(fhPadding==1) fhFrameSize++;



        return true;
    }

// ------------------------------- FUNKCJE DODATKOWE ---------------------------

    public static boolean isStegowalny( byte[] frameBits) {

        int temp;
        //int gdzieSkonczy = 21; // tyle pustych starcza ale nie zawsze ?!?
        int gdzieSkonczy = frameBits.length-1; // sprawdz wszystkie

        // start od 36, tam mogą być wolne miejsca
        for (int idx = 36; idx < gdzieSkonczy; idx++) {
            temp = frameBits[idx];
            if(temp!=frameBits[idx+1]) return false;
            
        }


        return true;
    }

    public static boolean isUnStegowalny(byte[] usArrBits) {

        if(usArrBits.length<4)return false;

        if(usArrBits[36]!=PlikMP3.TAG_ZNACZNIK[0])return false;
        if(usArrBits[37]!=PlikMP3.TAG_ZNACZNIK[1])return false;
        if(usArrBits[38]!=PlikMP3.TAG_ZNACZNIK[2])return false;
        if(usArrBits[39]!=PlikMP3.TAG_ZNACZNIK[3])return false;

        return true;

    }
// ------------------------------- FUNKCJE dziwne ------------------------------



// ******************************** PRYWATNE ***********************************
// *****************************************************************************
// ------------------------------- FUNKCJE KRYTYCZNE


// ------------------------------- FUNKCJE  POMOCNICZE CZY/SET -----------------

    public int getBitrateBit() {
        return fhBitrateBit;
    }

    public void setBitrateBit(int fhBitrateBit) {
        this.fhBitrateBit = fhBitrateBit;
    }

    public int getChannelMode() {
        return fhChannelMode;
    }

    public void setChannelMode(int fhChannelMode) {
        this.fhChannelMode = fhChannelMode;
    }

    public int getCopyright() {
        return fhCopyright;
    }

    public void setCopyright(int fhCopyright) {
        this.fhCopyright = fhCopyright;
    }

    public int getEmphasis() {
        return fhEmphasis;
    }

    public void setEmphasis(int fhEmphasis) {
        this.fhEmphasis = fhEmphasis;
    }

    public int length() {
        return fhFrameSize;
    }

    public long getLocation() {
        return fhLoc;
    }

    public void setLocation(long fhLoc) {
        this.fhLoc = fhLoc;
    }

    public int getModeExtension() {
        return fhModeExtension;
    }

    public void setModeExtension(int fhModeExtension) {
        this.fhModeExtension = fhModeExtension;
    }

    public int getMpegLayer() {
        return fhMpegLayer;
    }

    public void setMpegLayer(int fhMpegLayer) {
        this.fhMpegLayer = fhMpegLayer;
    }

    public int getMpegVer() {
        return fhMpegVer;
    }

    public void setMpegVer(int fhMpegVer) {
        this.fhMpegVer = fhMpegVer;
    }

    public int getOriginal() {
        return fhOriginal;
    }

    public void setOriginal(int fhOriginal) {
        this.fhOriginal = fhOriginal;
    }

    public int getPadding() {
        return fhPadding;
    }

    public void setPadding(int fhPadding) {
        this.fhPadding = fhPadding;
    }

    public int getPrivateBit() {
        return fhPrivateBit;
    }

    public void setPrivateBit(int fhPrivateBit) {
        this.fhPrivateBit = fhPrivateBit;
    }

    public int getProtection() {
        return fhProtection;
    }

    public void setProtection(int fhProtection) {
        this.fhProtection = fhProtection;
    }

    public int getSamplingRateBit() {
        return fhSamplingRateBit;
    }

    public void setSamplingRateBit(int fhSamplingRateBit) {
        this.fhSamplingRateBit = fhSamplingRateBit;
    }

}
